﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using AutoMapper;

using Revis.VClinicNet.Core.Domain;
using Revis.VClinicNet.Core.Domain.Repository;
using Revis.VClinicNet.Core.Domain.Credentials;
using Revis.VClinicNet.App.Internal.Dto;
using Revis.VClinicNet.App.Internal.Dto.Validation;


namespace Revis.VClinicNet.App.Internal.ServiceImpl
{
    public class WorkerUserService : IWorkerUserService
    {
        protected IWorkerUserRepository _workerUserRepository = null;
        protected IWorkerRepository _workerRepository = null;
        protected IPasswordEncrypter _encrypter = null;

        public WorkerUserService(IWorkerUserRepository iwur, IWorkerRepository iwr, IPasswordEncrypter encrypter)
        {
            _workerUserRepository = iwur;
            _workerRepository = iwr;
            _encrypter = encrypter;
        }

        public WorkerUserDto Find(string login, string password)
        {
            string passwordHash = _encrypter.Encrypt(password);
            WorkerUser user = _workerUserRepository.Find(login, passwordHash);
            WorkerUserDto dto = Mapper.Map<WorkerUser, WorkerUserDto>(user);
            return dto;
        }

        public WorkerUserDto Find(string login)
        {
            WorkerUser user = _workerUserRepository.Find(login);
            WorkerUserDto dto = Mapper.Map<WorkerUser, WorkerUserDto>(user);
            return dto;
        }


        public long Create(WorkerUserCreateDto createDto)
        {
            Validation.For<WorkerUserCreateDto>().Using<WorkerUserCreateDtoRules>().Check(createDto);

            string hashedPassword = _encrypter.Encrypt(createDto.Password);

            WorkerUser sameUser = _workerUserRepository.Find(createDto.Login, hashedPassword);
            if (sameUser != null) {
                throw new ClinicException("Użytkownik o takich danych już istnieje");
            }

            Worker worker = null;

            if (createDto.Role == WorkerUserRole.Doctor) {
                worker = new Doctor(createDto.FirstName, createDto.Surname);
            } else {
                worker = new Worker(createDto.FirstName, createDto.Surname);
            }

            WorkerUser newUser = new WorkerUser(
                createDto.Login,
                hashedPassword,
                worker,
                createDto.Role);

            _workerUserRepository.Store(newUser);

            return newUser.Id;
        }

        public TDto Find<TDto>(long userId)
        {
            WorkerUser user = _workerUserRepository.Find(userId);
            TDto dto = Mapper.Map<WorkerUser, TDto>(user);
            return dto;
        }

        public long Edit(WorkerUserEditDto editDto)
        {
            Validation.For<WorkerUserEditDto>().Using<WorkerUserEditDtoRules>().Check(editDto);

            WorkerUser user = _workerUserRepository.Find(editDto.Id);

            if (user == null) {
                throw new ClinicException("Nie znaleziono takiego użytkownika");
            }

            user.Change(
                editDto.Login,
                user.Password,
                user.Role);
            user.SetActivity(editDto.IsActive);

            if (user.Role == WorkerUserRole.Doctor) {
                user.RelatedWorker.SetActivity(editDto.IsActive);
            }

            _workerUserRepository.Store(user);

            return user.Id;
        }

        public long ChangePassword(WorkerUserModifyPasswordDto passwordDto)
        {
            Validation.For<WorkerUserModifyPasswordDto>()
                .Using<WorkerUserModifyPasswordDtoRules>().Check(passwordDto);

            WorkerUser user = _workerUserRepository.Find(passwordDto.Id);

            if (user == null) {
                throw new ClinicException("Nie znaleziono takiego użytkownika");
            }

            string hashedPassword = _encrypter.Encrypt(passwordDto.Password);

            user.Change(
                user.Login,
                hashedPassword,
                user.Role);

            _workerUserRepository.Store(user);

            return user.Id;
        }

        public IList<WorkerUserInfoDto> FindBy(string field, string value)
        {
            IList<WorkerUser> workerUsers = _workerUserRepository.FindBy(field, value);
            IList<WorkerUserInfoDto> workerInfos = Mapper.Map<IList<WorkerUser>, IList<WorkerUserInfoDto>>(workerUsers);
            return workerInfos;
        }

        public IList<WorkerUserInfoDto> FindBy(string field, string value, bool activity)
        {
            IList<WorkerUser> workerUsers = _workerUserRepository.FindBy(field, value, activity);
            IList<WorkerUserInfoDto> workerInfos = Mapper.Map<IList<WorkerUser>, IList<WorkerUserInfoDto>>(workerUsers);

            return workerInfos;
        }

        public bool Delete(long userId)
        {
            WorkerUser user = _workerUserRepository.Find(userId);
            if (user != null) {
                WorkerUserRole role = user.Role;
                if (role == WorkerUserRole.Recepcionist) {
                    _workerRepository.Delete(user.RelatedWorker);
                    _workerUserRepository.Delete(user);
                    return true;
                }
                if (role == WorkerUserRole.Doctor) {
                    user.SetInactive();
                    user.RelatedWorker.SetInactive();
                    _workerUserRepository.Store(user);
                    return true;
                }
                if (role == WorkerUserRole.Administrator) {
                    _workerRepository.Delete(user.RelatedWorker);
                    _workerUserRepository.Delete(user);
                    return true;
                }
            }
            return false;
        }



    }
}
